#include <set>
#include "label.h"
#include "qtch/log.h"
#include "table.h"

namespace qtch {
namespace orm {

static Logger::ptr logger = QTCH_LOG_NAME("orm");

Label::ptr Label::Create(const tinyxml2::XMLNode& node){
    const tinyxml2::XMLElement* element = node.ToElement();
    Label::ptr label_ptr;
    if(!element){
        label_ptr.reset(new StringLabel());
        if(!label_ptr->init(node.Value())){
            return nullptr;
        }
    }else{
        QTCH_LOG_ERROR(logger) << "unknow label node name=" << element->Name();
        return nullptr; 
    }
    return label_ptr; 
}

bool StringLabel::init(const tinyxml2::XMLNode& node) {
    if(node.ToElement()){
        QTCH_LOG_ERROR(logger) << "StringLabel can't init by XMLNode node node" << node.ToElement();
    }
    return init(node.Value());
}

bool StringLabel::init(const std::string& str) {
    QTCH_LOG_DEBUG(logger) << "StringLabel init str=" << str; 
    tinyxml2::XMLDocument doc;
    tinyxml2::XMLError error = doc.Parse(str.c_str(),str.length());
    if(error==tinyxml2::XMLError::XML_SUCCESS){
        QTCH_LOG_ERROR(logger) << "StringLabel can't init by str is XMLElement node str=" << str;
        return false;
    }
    std::vector<std::string> params = StringUtil::regexSearch(str,"#{\\w+(,\\w+=\\w+)*}");
    std::string resultStr = StringUtil::regexReplace(str,"#{\\w*(,\\w+=\\w+)*}","?");
    m_str = StringUtil::trim(resultStr);
    std::set<std::string> paramNames;
    for(size_t i = 0; i < params.size(); ++i){
        OrmParameter::ptr param(new OrmParameter);
        if(!param->init(params[i])){
            return false;
        }
        if(paramNames.count(param->getName())==1){
            QTCH_LOG_ERROR(logger) << "StringLabel init error by param name is existed name=" << param->getName();
            return false;
        }
        addBind(param);

    }
    return true;
}

std::string StringLabel::gen(std::shared_ptr<Table> table) {
    std::stringstream ss;
    ss << "    " << "__orm_sql << \" " ;
    size_t pos = 0;
    size_t to = m_str.find('\n');
    if(pos == std::string::npos){
        ss << m_str;
    }else{
        while(to!=std::string::npos){
            std::string sub = m_str.substr(pos,to - pos);
            ss <<" " << qtch::StringUtil::trim(sub)<< "\"" << std::endl;
            ss << "    << \"";
            pos = to+1;
            to = m_str.find('\n',pos);
        }
        ss << " " << qtch::StringUtil::trim(m_str.substr(pos));
    }

    ss << "\";" << std::endl;

    ss << "    __orm_stmt = __orm_conn->prepare(__orm_sql.str());" << std::endl;
    std::vector<OrmParameter::ptr> temp = getBindVec();
    std::vector<qtch::orm::Column::ptr>cols = table->getCols();
    for(size_t i=0;i<temp.size();++i){
        if(temp[i]->getType()==Column::Type::TYPE_TABLE){
            bool colFind = false;
            for(size_t j = 0; j < cols.size(); ++j){
                if(cols[j]->getName()==temp[i]->getName()){
                    ss << "    if(!__orm_entiry->" << getAsIsFunName(cols[j]->getName()) << "()){" << std::endl;
                    ss << "        __orm_stmt->" << cols[j]->getBindString() << "(__orm_paramNum++, __orm_entiry->" 
                       << GetAsMemberName(cols[j]->getName()) << ");" << std::endl; 
                    ss << "    } else {" << std::endl;
                    ss << "         __orm_stmt->bindNull(__orm_paramNum++);" << std::endl;
                    ss << "    }" << std::endl;
                    colFind = true;
                    break;
                }
            }
            if(!colFind){
                ss << "// unable find col name=" << temp[i]->getName() << std::endl;
            }

        }else {
            ss << "    __orm_stmt->" << Column::getBindString(temp[i]->getType())
               << "(__orm_paramNum++, " << temp[i]->getName() << ");" << std::endl;
        }
    }



    return ss.str();
}


}
}